package com.gin.kotlin.no_gay_alliance.fragment.main.me.item

import android.content.DialogInterface
import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.gin.kotlin.no_gay_alliance.R
import com.gin.kotlin.no_gay_alliance.adapter.item.AbstractItemAdapter
import com.gin.kotlin.no_gay_alliance.adapter.item.ItemGridAdapter
import com.gin.kotlin.no_gay_alliance.adapter.item.ItemLinerAdapter
import com.gin.kotlin.no_gay_alliance.app.App
import com.gin.kotlin.no_gay_alliance.argument.ItemArgument
import com.gin.kotlin.no_gay_alliance.argument.ItemArgument.Mode
import com.gin.kotlin.no_gay_alliance.base.AbstractBindingFragment
import com.gin.kotlin.no_gay_alliance.base.AlertDialogUtils
import com.gin.kotlin.no_gay_alliance.base.ClipboardUtils
import com.gin.kotlin.no_gay_alliance.base.IntRangeTextWatcher
import com.gin.kotlin.no_gay_alliance.callback.RCallback
import com.gin.kotlin.no_gay_alliance.databinding.DialogItemUseToReplyBinding
import com.gin.kotlin.no_gay_alliance.databinding.FragmentItemBinding
import com.gin.kotlin.no_gay_alliance.model.ItemDataModel
import com.gin.kotlin.no_gay_alliance.provider.ngaphp.AbstractCachedDataProvider
import com.gin.kotlin.no_gay_alliance.provider.ngaphp.ItemInventoryProvider
import com.gin.kotlin.no_gay_alliance.provider.ngaphp.ItemStoreProvider
import com.gin.nga.callback.NgaCallback
import com.gin.nga.enums.param.ItemType
import com.gin.nga.response.base.NgaResponse
import com.gin.nga.response.base.SingleData
import com.gin.nga.response.item.ItemData
import com.gin.nga.response.item.ItemInfo
import retrofit2.Call
import retrofit2.Response

/**
 * 抽象的道具Fragment，仓库和商店共用
 * @property adapter 适配器
 * @property argument 参数
 */
abstract class AbstractItemFragment : AbstractBindingFragment<FragmentItemBinding>(), RCallback<ItemDataModel, ItemArgument>, NgaCallback<List<String>> {

    private lateinit var adapter: AbstractItemAdapter<*>
    private lateinit var argument: ItemArgument

    override fun onCreateView() {
        val b = this.b ?: return
        // 根据模式为 RecyclerView 装载 layoutManager
        b.recyclerView.layoutManager = when (argument.mode) {
            Mode.Grid -> GridLayoutManager(requireContext(), 3, LinearLayoutManager.VERTICAL, false)
            Mode.Linear -> LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
        }
        b.swipeRefreshLayout.setOnRefreshListener {
            argument = argument.copy(page = 1)
            adapter.clear()
            request(true)
        }
        // 根据模式为 RecyclerView 装载适配器
        this.adapter = when (argument.mode) {
            Mode.Grid -> ItemGridAdapter(requireContext(), handler!!) { onClickItem(it?.tag as ItemInfo) }
            Mode.Linear -> ItemLinerAdapter(requireContext(), handler!!) { onClickItem(it?.tag as ItemInfo) }
        }
        b.recyclerView.adapter = adapter

        // 配置单选框组
        b.radioGroupItemType.also { rg ->
            // 只在Linear 模式显示
            rg.visibility = if (argument.mode == Mode.Grid) View.GONE else View.VISIBLE
            rg.check(
                when (argument.type) {
                    ItemType.ACTIVATION_CODE -> R.id.radio_button_item_activation_code
                    ItemType.MEDAL -> R.id.radio_button_item_medal
                    ItemType.TO_USER -> R.id.radio_button_item_to_user
                    ItemType.TO_REPLY -> R.id.radio_button_item_to_reply
                    else -> R.id.radio_button_item_all
                }
            )
            rg.setOnCheckedChangeListener { _, checkedId ->
                val type = when (checkedId) {
                    R.id.radio_button_item_activation_code -> ItemType.ACTIVATION_CODE
                    R.id.radio_button_item_medal -> ItemType.MEDAL
                    R.id.radio_button_item_to_user -> ItemType.TO_USER
                    R.id.radio_button_item_to_reply -> ItemType.TO_REPLY
                    else -> null
                }
                argument = argument.copy(type = type, page = 1)
                adapter.clear()
                uiDelayed(200) { request() }
            }
        }


        // 发送请求
        request()
    }

    override fun handleArguments(bundle: Bundle) {
        this.argument = parseBundle(bundle, ItemArgument::class.java.simpleName, ItemArgument::class.java)
    }

    fun request(ignoreCache: Boolean = false) {
        val b = this.b ?: return
        b.tvWarning.visibility = View.GONE
        b.swipeRefreshLayout.isRefreshing = true
        provider().enqueue(params = argument, ignoreCache = ignoreCache, callback = this)
    }

    /**
     * 请求成功，替换数据
     * @param data ItemDataModel
     */
    override fun onSuccess(data: ItemDataModel, ignoreCache: Boolean) {
        val b = this.b ?: return
        b.swipeRefreshLayout.isRefreshing = false
        // 按类型过滤
        val list = data.data?.filter { argument.type == null || it.type == argument.type }

        adapter.pushData(list)
        // 如果结果非空，继续拉取
        if (data.hasNext) {
            argument = argument.copy(page = argument.page + 1)
            uiDelayed(200) { request(ignoreCache) }
        }
    }

    override fun onError(errorMessage: String) {
        val b = this.b ?: return
        b.swipeRefreshLayout.isRefreshing = false
        b.tvWarning.visibility = View.VISIBLE
        b.tvWarning.text = errorMessage
    }

    /**
     * 数据提供者，应为 [ItemInventoryProvider] 或 [ItemStoreProvider]
     * @return AbstractCachedDataProvider<ItemArgument, SingleData<ItemData>, List<ItemInfo>>
     */
    abstract fun provider(): AbstractCachedDataProvider<ItemArgument, SingleData<ItemData>, ItemDataModel>

    /**
     * 点击适配器中Item的响应
     * @param itemInfo [ItemInfo]
     */
    abstract fun onClickItem(itemInfo: ItemInfo)

    override fun onSuccess(call: Call<NgaResponse<List<String>>>, response: Response<NgaResponse<List<String>>>, body: NgaResponse<List<String>>?, data: List<String>?) {
        data?.get(0)?.also { AlertDialogUtils.builder(requireContext(), message = it).show() }
    }

    override fun onError(call: Call<NgaResponse<List<String>>>, response: Response<NgaResponse<List<String>>>, body: NgaResponse<List<String>>?, errorMessage: String) {
        AlertDialogUtils.builder(requireContext(), message = errorMessage).show()
    }

    /**
     * 获取用户id，如果未直接提供，弹窗获取
     * @param userId Long?
     * @param then Function1<[@kotlin.ParameterName] Long, Unit>
     */
    fun obtainUserId(userId: Long? = argument.userId, then: (userId: Long) -> Unit) {
        if (userId != null)
            then.invoke(userId)
        else {
            // 弹窗选择购买数量
            val editText = EditText(requireContext())
            editText.hint = getString(R.string.edit_text_hint_enter_user_id)
            editText.inputType = InputType.TYPE_CLASS_NUMBER
            editText.addTextChangedListener(IntRangeTextWatcher(editText, 1))
            AlertDialogUtils.builder(requireContext(),
                title = getString(R.string.dialog_title_item_use_to_user),
                contentView = editText,
                listener = { _, which ->
                    if (which == DialogInterface.BUTTON_POSITIVE) then.invoke(editText.text.toString().toLong())
                })
                .setNeutralButton(getString(R.string.dialog_button_use_to_self)) { _, _ -> then.invoke(App.INSTANCE.account.userId) }
                .show()

            // 如果剪贴板中有数字，直接粘贴
            ClipboardUtils.getText(0)?.toLongOrNull()?.takeIf { it > 0 }?.also { editText.setText(it.toString()) }
        }
    }

    fun obtainTopicId(topicId: Long? = argument.topicId, replyId: Long? = argument.replyId, then: (topicId: Long, replyId: Long?) -> Unit) {
        if (topicId != null)
            then.invoke(topicId, replyId)
        else {
            val binding = DialogItemUseToReplyBinding.inflate(LayoutInflater.from(requireContext()))
            binding.editTextTopicId.addTextChangedListener(IntRangeTextWatcher(binding.editTextTopicId, 1))
            binding.editTextReplyId.addTextChangedListener(IntRangeTextWatcher(binding.editTextReplyId, 1))

            AlertDialogUtils.builder(requireContext(),
                title = getString(R.string.dialog_title_item_use_to_reply),
                contentView = binding.root,
                listener = { _, which ->
                    val tid = binding.editTextTopicId.text.toString().toLongOrNull()
                    val pid = binding.editTextReplyId.text.toString().toLongOrNull()
                    if (tid != null && which == DialogInterface.BUTTON_POSITIVE) then.invoke(tid, pid)
                }).show()

        }
    }
}
